package com.github.baichuan.application.scaffold.rest.domain.authorization;

import com.github.baichuan.application.scaffold.rest.domain.application.Application;
import com.github.baichuan.application.scaffold.rest.domain.application.ApplicationService;
import com.github.baichuan.application.scaffold.rest.domain.identity.ApplicationMember;
import com.github.baichuan.application.scaffold.rest.domain.identity.ApplicationMemberService;
import com.github.baichuan.application.scaffold.rest.domain.organization.OrgService;
import com.github.baichuan.application.scaffold.rest.domain.organization.Tenant;
import com.github.baichuan.application.scaffold.rest.jpa.authorization.ResourceRepository;
import com.github.baichuan.application.scaffold.rest.jpa.authorization.RoleRepository;
import com.github.baichuan.web.dto.Result;
import com.github.baichuan.application.scaffold.rest.dto.role.RoleForm;
import com.github.baichuan.web.error.NoSuchEntityException;
import com.github.baichuan.utils.SnowFlake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
@Transactional(rollbackFor = Exception.class)
public class RoleService {
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private ApplicationService applicationService;
    @Autowired
    private ApplicationMemberService applicationMemberService;
    @Autowired
    private OrgService orgService;
    @Autowired
    private SnowFlake snowFlake;

    public Role find(String id) {
        return roleRepository.findById(id).orElseThrow(() -> new NoSuchEntityException("角色id错误"));
    }

    public Role find(Application application, String id) {
        return roleRepository.find(application, id).orElseThrow(() -> new NoSuchEntityException("角色不存在"));
    }

    public Page<Role> query(Specification<Role> specification, Pageable pageable) {
        return roleRepository.findAll(specification, pageable);
    }

    public List<Role> get(Specification<Role> specification) {
        return roleRepository.findAll(specification);
    }

    /**
     * 获取机构可用的角色列表
     * 角色列表包括机构自建的和分配给机构下用户的所有角色
     * @return
     */
    public List<Role> getAvailableRoles(String application, String orgUid){
        return roleRepository.getAvailables(application, orgUid);
    }

    /**
     * 初始化创建管理员角色
     */
    public Result add(String applicationCode, RoleForm form){
        Application application = applicationService.findByCode(applicationCode);
        Tenant tenant = null;

        Optional<Role> duplicationName = roleRepository.find(application.getId(), tenant, form.getName().trim());
        if (duplicationName.isPresent()) {
            return Result.fail("角色名称重复");
        }

        Role role = new Role();
        role.setId(snowFlake.nextBase62Id());
        role.setApplication(application);
        merge(form, role);
        roleRepository.save(role);

        return Result.success("角色添加成功", role.getId());
    }

    public Result add(String applicationCode, String memberUid, RoleForm form) {
        Application application = applicationService.findByCode(applicationCode);
        ApplicationMember member = applicationMemberService.find(applicationCode, memberUid);

        Tenant tenant = null;
        if(application.getTenant() == Application.TenantMode.MULTIPLE && !member.isAdmin()){
            // 多租户模式下非管理员用户创建的角色的机构为创建用户的顶级机构
//            org = orgService.find(application, member.getOrg().topUid());
            tenant = orgService.find(application, member.getOrg().topUid()).getTenant();
        }

        Optional<Role> duplicationName = roleRepository.find(application.getId(), tenant, form.getName().trim());
        if (duplicationName.isPresent()) {
            return Result.fail("角色名称重复");
        }

        Role role = new Role();
        role.setId(snowFlake.nextBase62Id());
        role.setApplication(application);
//        role.setOrg(org);
        role.setTenant(tenant);
        merge(form, role);
        roleRepository.save(role);

        return Result.success("角色添加成功", role.getId());
    }

    private static void merge(RoleForm form, Role role) {
        role.setName(form.getName().trim());
        role.setCode(form.getCode());
        role.setIntro(form.getIntro());
    }

    public Result edit(String applicationCode, String id, RoleForm form) {
        Application application = applicationService.findByCode(applicationCode);
        Role role = find(application, id);

        Optional<Role> duplicationName = roleRepository.find(role.getApplication().getId(), role.getTenant(), form.getName().trim());
        if (duplicationName.isPresent() && duplicationName.get().getId().equals(id)) {
            return Result.fail("角色名称重复");
        }

        merge(form, role);
        roleRepository.save(role);

        return Result.success("角色保存成功");
    }

    public Result remove(String appCode, String id) {
        Application application = applicationService.findByCode(appCode);
        if (roleRepository.countMembers(id) > 0) {
            return Result.fail("不能删除被使用的角色");
        }
        Optional<Role> optional = roleRepository.find(application, id);
        if (optional.isPresent()) {
            roleRepository.delete(optional.get());
        }
        return Result.success("角色删除成功");
    }

    /**
     * 获取角色授权的资源列表
     */
    public List<Resource> getResources(String appCode, String id) {
        Application application = applicationService.findByCode(appCode);
        Role role = find(application, id);
        return role.getResources();
        //return roleRepository.getResources(role.getId());
    }

    /**
     * 角色授权
     */
    public Result addAuthorize(String applicationCode, String roleId, String resourceId){
        Application application = applicationService.findByCode(applicationCode);
        Role role = find(application, roleId);
        Resource resource = resourceService.find(applicationCode, resourceId);

        if(!role.getResources().stream().anyMatch(r -> r.getId().equals(resourceId))){
            role.getResources().add(resource);
            roleRepository.save(role);
        }

        return Result.success(resource.getName() + "添加成功");
    }

    public Result removeAuthorize(String applicationCode, String roleId, String resourceId){
        Application application = applicationService.findByCode(applicationCode);
        Role role = find(application, roleId);
        Resource resource = resourceService.find(applicationCode, resourceId);

        if(role.getResources().stream().anyMatch(r -> r.getId().equals(resourceId))){
            role.getResources().remove(resource);
            roleRepository.save(role);
        }

        return Result.success(resource.getName() + "移除成功");
    }

    /**
     * 修改功能菜单授权
     */
//    public Result authorize(String appCode, short id, List<String> resourceIds) {
//        Application application = applicationService.find(appCode);
//        Role role = find(application, id);
//        List<Resource> resources = resourceRepository.findAll(application, resourceIds);
//        if(role.getResources() == null){
//            role.setResources(new LinkedList<>());
//        }
//        CollectionUtils.update(role.getResources(), resources);
//        roleRepository.save(role);
//        return Result.success("角色授权成功");
//    }
}
